/* COPYRIGHT_CHUNFENG */
#include <unistd.h>
#include "cf_fstab_file.h"
#include "cf_std.h"
#include "cf_common.h"

static void __fstab_line_comment_value(CFFstabLine* line)
{
	line->dev = cf_string_new("");
	line->mountPoint = cf_string_new("");
	line->type = cf_string_new("");
	line->options = cf_string_new("");
}

CFListHead* cf_fstab_line_parse_new(char* start, char* end)
{
	CFFstabLine *line = malloc(sizeof(CFFstabLine));
	
    cf_list_init(&line->list);
	cf_char_strip(&start, &end, TRUE, TRUE);
	if(start == end){
	//printf("start==end\n");
		if(cf_char_is_blank(*start) || *start == '#'){

			line->is_comment = TRUE;
			//puts("comment");
			if(cf_char_is_blank(*start)){
					//printf("Got blank==>line->comment=%d\n", *start);	
				line->comment = cf_string_new("");
			}
			else {
				line->comment = cf_string_new("#");
		//printf("Got #==>line->comment=%s\n", line->comment->str);				
				}
			__fstab_line_comment_value(line);
			return &line->list;
		}else{
			free(line);
			return NULL;
		}
	}
	
	if(*start == '#'){
		line->is_comment = TRUE;
		line->comment = cf_string_new_len(start, end - start +1);
		//printf("==>parsing comment: %s\n", line->comment->str);
		__fstab_line_comment_value(line);
		return &line->list;
	}else{
		char *dev_start, *dev_end;
		char *mountPoint_start, *mountPoint_end;
		char *type_start, *type_end;
		char *options_start, *options_end;
		char *dump_start, *dump_end;
		char *pass_start, *pass_end;
		dev_start = start;
		dev_end = strblank(dev_start);
		mountPoint_start = strnblank(dev_end--);
		mountPoint_end = strblank(mountPoint_start);
		type_start = strnblank(mountPoint_end--);
		type_end = strblank(type_start);
		options_start = strnblank(type_end--);
		options_end = strblank(options_start);
		dump_start = strnblank(options_end--);
		dump_end = strblank(dump_start);
		pass_start = strnblank(dump_end--);
		pass_end = end;
		if(dev_start && dev_end && 
			mountPoint_start && mountPoint_end && 
			type_start && type_end &&
			options_start && options_end &&
			dump_start && dump_end &&
			pass_start && pass_end){
			CFString *dumpString, *passString;
			line->dev = cf_string_new_start_end(dev_start, dev_end);
			line->mountPoint = cf_string_new_start_end(mountPoint_start, mountPoint_end);
			line->type = cf_string_new_start_end(type_start, type_end);
			line->options = cf_string_new_start_end(options_start, options_end);
			dumpString = cf_string_new_start_end(dump_start, dump_end);
			line->dump = atoi(cf_string_get_str(dumpString));
			cf_string_free(dumpString);
			passString = cf_string_new_start_end(pass_start, pass_end);
			line->pass = atoi(cf_string_get_str(passString));
			cf_string_free(passString);
		}
		line->is_comment = FALSE;
		line->comment = cf_string_new("");
		return &line->list;
	}
}

CFFstabLine* cf_fstab_line_new(int is_comment, const char* comment, 
	const char* dev, const char* mountPoint, 
	const char* type, const char* options, 
	int dump, int pass)
{
	CFFstabLine* line = (CFFstabLine*)malloc(sizeof(CFFstabLine));
    cf_list_init(&line->list);
	if(is_comment){
		line->is_comment = TRUE;
		line->comment = cf_string_new(comment);
		__fstab_line_comment_value(line);
		return line;
	}else{
		line->is_comment = FALSE;
		line->comment = cf_string_new("");
		line->dev = cf_string_new(dev);
		line->mountPoint = cf_string_new(mountPoint);
		line->type = cf_string_new(type);
		line->options = cf_string_new(options);
		line->dump = dump;
		line->pass = pass;
		return line;
	}
}

void cf_fstab_line_free(CFListHead* node)
{  
	CFFstabLine* line;
    line = container_of(node, CFFstabLine, list);
    cf_string_free(line->comment);
    cf_string_free(line->dev);
    cf_string_free(line->mountPoint);
    cf_string_free(line->type);
    cf_string_free(line->options);
    free(line);
}

CFFstabLine* cf_fstab_line_get_next(CFFstabLine* line)
{
    return container_of(cf_list_get_next(&line->list), CFFstabLine, list);
}

void cf_fstab_line_append(CFFstabLine* line, CFFstabLine* newLine)
{
    cf_list_insert_pre(&line->list, &newLine->list);
}

int cf_fstab_line_write(CFListHead* node, int fd)
{
    CFFstabLine* line;
    line = container_of(node, CFFstabLine, list);
	int writed=0;
	char digBuf[2];
	if(line->is_comment){
		write(fd, line->comment->str, line->comment->len);
	}else{
		//puts("H");
		writed += write(fd, line->dev->str, line->dev->len);
		writed += write(fd, "\t", 1);
		writed += write(fd, line->mountPoint->str, line->mountPoint->len);
		writed += write(fd, "\t", 1);
		writed += write(fd, line->type->str, line->type->len);
		writed += write(fd, "\t", 1);
		writed += write(fd, line->options->str, line->options->len);
		writed += write(fd, "\t", 1);
		sprintf(digBuf, "%d", line->dump);
		writed += write(fd, digBuf, 1);
		writed += write(fd, "\t", 1);
		sprintf(digBuf, "%d", line->pass);
		writed += write(fd, digBuf, 1);
		//puts("hhhhhhhhhhhhhhhhhh");
	}
	return writed;
}

char* cf_fstab_line_get_dev(CFFstabLine* line)
{
	return cf_string_get_str(line->dev);
}

char* cf_fstab_line_get_mount_point(CFFstabLine* line)
{
	return cf_string_get_str(line->mountPoint);
}

int cf_fstab_line_is_comment(CFFstabLine* line)
{
	return line->is_comment;
}

void cf_fstab_line_set(CFFstabLine* line, const char* dev, 
	const char* mountPoint, const char* type, 
	const char* options, int dump, int pass)
{
	cf_string_safe_cp(line->dev, dev);
	cf_string_safe_cp(line->mountPoint, mountPoint);
	cf_string_safe_cp(line->type, type);
	cf_string_safe_cp(line->options, options);
	line->dump = dump;
	line->pass = pass;
}

CFFstabFile* cf_fstab_file_new(const char* fileUri)
{
	CFFstabFile* file;
	CFListHead* node;
	node = cf_list_file_new(fileUri, cf_fstab_line_parse_new);
	if(!node)
		return NULL;
	file = malloc(sizeof(CFFstabFile));
    cf_list_init(&file->head.list);
    cf_fstab_line_append(container_of(node, CFFstabLine, list), &file->head);
	file->fileUri = cf_string_new(fileUri);
	return file;
}

void cf_fstab_file_free(CFFstabFile* file)
{
	cf_list_file_free(&file->head.list, cf_fstab_line_free);
	cf_string_free(file->fileUri);
	free(file);
}

CFFstabLine* cf_fstab_file_get(CFFstabFile* file, const char* dev)
{
    CFFstabLine* tmpLine = cf_fstab_line_get_next(&file->head);
	do{
		if(!cf_fstab_line_is_comment(tmpLine) && 0 == strcmp(cf_fstab_line_get_dev(tmpLine), dev))
			return tmpLine;
        tmpLine = cf_fstab_line_get_next(tmpLine);
	}while(tmpLine != &file->head);
	return NULL;
}

void cf_fstab_file_set(CFFstabFile* file, const char* dev, 
	const char* mountPoint, const char* type, 
	const char* options, int dump, int pass)
{
	CFFstabLine *tmpLine;
	tmpLine = cf_fstab_line_get_next(&file->head);
	do{
		if(!cf_fstab_line_is_comment(tmpLine) && 0 == strcmp(cf_fstab_line_get_mount_point(tmpLine), mountPoint)){
            cf_fstab_line_set(tmpLine, dev, mountPoint, type, options, dump, pass);
			return;
		}
        tmpLine = cf_fstab_line_get_next(tmpLine);
	}while(tmpLine != &file->head);
	cf_fstab_line_append(&file->head, cf_fstab_line_new(FALSE, NULL, dev, mountPoint, type, options, dump, pass));
	return;
}

int cf_fstab_file_write(CFFstabFile* file, int fd)
{
	return cf_list_file_write(&file->head.list, fd, cf_fstab_line_write);
}

int cf_fstab_file_print(CFFstabFile* file)
{
	return cf_fstab_file_write(file, 1);
}

int cf_fstab_file_save(CFFstabFile* file, const char* fileUri)
{
	if(!fileUri)
		fileUri = cf_string_get_str(file->fileUri);
	return cf_list_file_save(&file->head.list, fileUri, cf_fstab_line_write);
}
